package org.jeecg.access.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.jeecg.access.entity.dto.MediaDTO;
import org.jeecg.access.platform.constant.DataState;
import org.jeecg.access.platform.constant.MediaType;
import org.jeecg.access.platform.entity.publish.Media;
import org.jeecg.access.platform.mapper.MediaMapper;
import org.jeecg.access.platform.service.MediaService;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.UUIDGenerator;
import org.jeecg.modules.oss.entity.OSSFile;
import org.jeecg.modules.oss.service.IOSSFileService;
import org.jeecg.util.DateTimeUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: todo
 * @author: taogang
 * @date: 2025/8/13 16:18
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {

    /**

     媒体资源数据访问层接口，用于数据库操作
     */
    private final MediaMapper mediaMapper;

    /**

     OSS 文件服务，用于文件上传至对象存储
     */
    private final IOSSFileService iossFileService;

    /**

     构造函数注入依赖
     @param mediaMapper 媒体资源数据访问接口
     @param iossFileService OSS 文件上传服务
     */
    public MediaServiceImpl(MediaMapper mediaMapper, IOSSFileService iossFileService) {
        this.mediaMapper = mediaMapper;
        this.iossFileService = iossFileService;
    }

    /**

     批量保存媒体资源信息
     处理流程：解析文件信息 -> 上传至 OSS -> 提取媒体属性（宽高 / 时长）-> 封装数据对象
     @param mediaDTOList 媒体 DTO 列表，包含待上传的文件及基础描述信息
     @return 处理完成的媒体资源列表（包含存储地址、属性等完整信息）
     */
    @Override
    public List<Media> saveMediaList(List<MediaDTO> mediaDTOList) {
            // 初始化媒体资源列表，预设容量避免动态扩容开销
        List<Media> mediaList = new ArrayList<>(mediaDTOList.size());
            // 获取当前时间戳（格式：yyyyMMddHHmmss），用于统一设置创建时间
        String currentTime = DateTimeUtil.getCurrentTimestamp();
            // 获取当前登录用户账号，作为创建人标识
        String creator = getCurrentUsername();
            // 遍历处理每个媒体 DTO
        for(MediaDTO mediaDTO : mediaDTOList) {
                // 获取上传的文件对象
            MultipartFile file = mediaDTO.getFile();
            // 跳过空文件，避免无效处理
            if(file == null || file.isEmpty()) {
                log.warn("跳过空文件，媒体名称：{}", mediaDTO.getName());
                continue;
            }
            // 初始化媒体实体对象
            Media media = new Media();
            // 设置基础属性
            media.setId(UUIDGenerator.generate()); // 生成唯一 ID
            media.setName(mediaDTO.getName()); // 媒体名称（来自 DTO）
            media.setDescription(mediaDTO.getDesc()); // 媒体描述（来自 DTO）
            media.setCreateTime(currentTime); // 创建时间（统一时间戳）
            media.setCreator(creator); // 创建人（当前登录用户）
            media.setState(DataState.INIT); // 初始状态（正常可用）
            media.setFileSize(file.getSize()); // 文件大小（字节）
            // 处理原始文件名（避免空指针）
            String originalFileName = file.getOriginalFilename();
            media.setFileName(originalFileName != null ? originalFileName : "unknown_file");
                // 解析文件类型（主类型 type 和子类型 subType）
            String contentType = file.getContentType(); // 获取 MIME 类型（如 image/jpeg）
            String type = null; // 主类型（image/voice/video/thumb）
            String subType = "unknown"; // 子类型（如 jpeg/mp3/mp4）
                // 优先通过 Content-Type 解析类型（更可靠）
            if(contentType != null) {
                if(contentType.startsWith(MediaType.IMAGE + "/")) {
                    // 图片类型（如 image/jpeg -> type=image, subType=jpeg）
                    type = MediaType.IMAGE;
                    subType = contentType.substring(MediaType.IMAGE.length() + 1).toLowerCase();
                } else if(contentType.startsWith(MediaType.VOICE + "/")) {
                    // 音频类型（如 voice/mp3 -> type=voice, subType=mp3）
                    type = MediaType.VOICE;
                    subType = contentType.substring(MediaType.VOICE.length() + 1).toLowerCase();
                } else if(contentType.startsWith(MediaType.VIDEO + "/")) {
                    // 视频类型（如 video/mp4 -> type=video, subType=mp4）
                    type = MediaType.VIDEO;
                    subType = contentType.substring(MediaType.VIDEO.length() + 1).toLowerCase();
                } else if(contentType.startsWith(MediaType.THUMB + "/")
                        || "application/octet-stream".equals(contentType)) {
                        // 缩略图类型（可能为特定类型或二进制流）
                    type = MediaType.THUMB;
                }
            }
                // 若 Content-Type 解析失败，通过文件后缀补充判断
            if(type == null && originalFileName != null && originalFileName.contains(".")) {
                // 提取文件后缀（如 "image.jpg" -> "jpg"）
                String suffix = originalFileName.substring(originalFileName.lastIndexOf(".") + 1).toLowerCase();
                // 根据后缀匹配类型
                if(suffix.matches("jpg|jpeg|png|gif|bmp|webp")) {
                    type = MediaType.IMAGE;
                    subType = suffix;
                } else if(suffix.matches("mp3|wav|amr|ogg")) {
                    type = MediaType.VOICE;
                    subType = suffix;
                } else if(suffix.matches("mp4|avi|mov|flv|mkv")) {
                    type = MediaType.VIDEO;
                    subType = suffix;
                } else if(suffix.matches("jpg|png|jpeg")) {
                    // 缩略图通常为图片格式
                    type = MediaType.THUMB;
                    subType = suffix;
                } else {
                    // 非指定类型默认按缩略图处理（可根据业务调整）
                    type = MediaType.THUMB;
                    log.warn("文件类型未知，默认按缩略图处理，文件名：{}", originalFileName);
                }
            }
                // 设置类型信息
            media.setType(type);
            media.setSubType(subType);
            // 处理文件上传及属性解析
            InputStream inputStream = null;
            try {
                    // 1. 上传文件至 OSS，获取存储 URL
                OSSFile ossFile = iossFileService.upload(file);
                media.setUrl(ossFile.getUrl()); // 设置文件访问地址
                    // 2. 根据类型解析媒体属性（仅处理需要的类型，减少资源消耗）
                if(MediaType.IMAGE.equals(type)) {
                    // 图片：解析宽高
                    inputStream = file.getInputStream();
                    BufferedImage image = ImageIO.read(inputStream);
                    if(image != null) {
                        media.setWidth(image.getWidth()); // 图片宽度（像素）
                        media.setHeight(image.getHeight()); // 图片高度（像素）
                    } else {
                        log.warn("图片解析失败，无法获取宽高，文件 ID：{}", media.getId());
                    }
                } else if(MediaType.VIDEO.equals(type)) {
                    // 视频：解析宽高和时长
                    inputStream = file.getInputStream();
                    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
                    grabber.start(); // 初始化解析器
                    media.setWidth(grabber.getImageWidth()); // 视频宽度（像素）
                    media.setHeight(grabber.getImageHeight()); // 视频高度（像素）
                    // 时长转换：微秒 -> 秒（FFmpeg 返回单位为微秒）
                    media.setDuration((int)(grabber.getLengthInTime() / 1000000));
                    grabber.stop(); // 停止解析器，释放资源
                }
                // 音频（voice）和缩略图（thumb）无需解析宽高 / 时长，跳过处理
            } catch(Exception e) {
                // 捕获异常但不中断流程，记录错误日志
                log.error("处理媒体文件时发生异常，文件 ID：{}，错误信息：{}", media.getId(), e.getMessage(), e);
            } finally {
                // 手动关闭输入流，避免资源泄露
                if(inputStream != null) {
                    try {
                        inputStream.close();
                    } catch(IOException e) {
                        log.error("关闭输入流失败，文件 ID：{}", media.getId(), e);
                    }
                }
            }
            // 将处理完成的媒体对象添加到列表
            mediaList.add(media);
        }
        // 批量保存到数据库（补充数据库持久化逻辑，根据业务需求调整）
        if(!mediaList.isEmpty()) {
            mediaMapper.batchInsert(mediaList);
            log.info("批量保存媒体资源成功，数量：{}", mediaList.size());
        }
        return mediaList;
    }

    @Override
    public List<Media> getMediasByIds(List<String> mediaIds) {
        if (CollectionUtils.isEmpty(mediaIds)) {
            return new ArrayList<>(0);
        }

        // 构建查询条件
        QueryWrapper<Media> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", mediaIds);
        queryWrapper.eq("state", DataState.INIT); // 只查询正常状态的媒体

        return list(queryWrapper);
    }

    /**

     获取当前登录用户的用户名
     @return 用户名
     */
    private String getCurrentUsername() {
        LoginUser sysUser =(LoginUser) SecurityUtils.getSubject().getPrincipal();
        return sysUser.getUsername();
    }

    /**

     获取当前登录用户的 ID
     @return 用户 ID
     */
    private String getCurrentUserId() {
        LoginUser sysUser =(LoginUser) SecurityUtils.getSubject().getPrincipal();
        return sysUser.getId();
    }
}
